package com.yanqu.road.server.gameplayer.module.activity.lanruosi;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ConditionTypeValueArgs;
import com.yanqu.road.entity.activity.lanruosi.AttackMonsterResult;
import com.yanqu.road.entity.activity.lanruosi.LanRuoSiConfig;
import com.yanqu.road.entity.activity.lanruosi.LanRuoSiUserData;
import com.yanqu.road.entity.activity.lanruosi.config.LanRuoSiScoreConfigInfo;
import com.yanqu.road.entity.activity.tripletown.*;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.LogLanRuoSiEliminate1;
import com.yanqu.road.entity.log.LogLanRuoSiEliminate2;
import com.yanqu.road.entity.log.LogLanRuoSiEnergy;
import com.yanqu.road.logic.bussiness.activity.LanRuoSiBussiness;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.pb.activity.LanRuoSiProto;
import com.yanqu.road.pb.activity.TripleTownProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.lanruosi.LanRuoSiMgr;
import com.yanqu.road.server.manger.activity.tripletown.EliminateLogic;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.pb.LanRuoSiPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;

import java.util.List;
import java.util.Map;

public class LanRuoSiModule extends GeneralModule {

    private LanRuoSiUserData userData;

    public LanRuoSiModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        if (config != null && ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            userData = LanRuoSiBussiness.getLanRuoSiUserData(config.getActivityInfo().getActivityId(), getUserId());
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                LanRuoSiBussiness.addLanRuoSiUserData(userData);
            } else if (userData.isUpdateOption()) {
                LanRuoSiBussiness.updateLanRuoSiUserData(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        syncConfig();
        initUserData();
        syncUserData();
    }

    /**
     * 初始化玩家数据
     */
    public synchronized void initUserData() {
        // 系统未解锁
        if (!SystemOpenMgr.systemOpen(player, eSystemId.LanRuoSiActivity.getValue())) {
            return;
        }

        // 没有活动
        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        ActivityInfo activityInfo = config.getActivityInfo();

        // 已经有数据了
        if (userData != null && userData.getActivityId() == activityInfo.getActivityId()) {
            return;
        }

        LanRuoSiUserData tmpUserData = new LanRuoSiUserData();
        tmpUserData.setActivityId(activityInfo.getActivityId());
        tmpUserData.setUserId(getUserId());
        tmpUserData.setScore(0);
        tmpUserData.setEnergy(config.getMaxEnergy());
        tmpUserData.setLastRecTime(System.currentTimeMillis());
        tmpUserData.setGuideIndex(0);

        // boss npc
        tmpUserData.setWaveNum(1);
        tmpUserData.setRound(1);
        List<Monster> newList = new ArrayList<>();
        LanRuoSiMgr.getNextWaveMonsterList(0, newList);
        tmpUserData.setMonsterList(newList);

        // 单倍格子
        int guideIndex = tmpUserData.getGuideIndex();
        int[] initBlock = config.getInitBlock();
        int[][] blockList1 = new int[LanRuoSiMgr.MAX_HEIGHT][LanRuoSiMgr.MAX_WIDTH];
        for (int y = 0; y < blockList1.length; y++) {
            for (int x = 0; x < blockList1[y].length; x++) {
                blockList1[y][x] = initBlock[guideIndex++];
            }
        }
        tmpUserData.setBlockList(blockList1, 1);
        tmpUserData.setGuideIndex(guideIndex);

        // 八倍格子
        int index = 0;
        int[] initBlockMulti = config.getInitBlockMulti();
        int[][] blockList8 = new int[LanRuoSiMgr.MAX_HEIGHT][LanRuoSiMgr.MAX_WIDTH];
        for (int y = 0; y < blockList8.length; y++) {
            for (int x = 0; x < blockList8[y].length; x++) {
                blockList8[y][x] = initBlockMulti[index++];
            }
        }
        tmpUserData.setBlockList(blockList8, 8);

        // 十六倍新增数据
        if (config.getFastUnlockVipLevel() != Integer.MAX_VALUE) {
            index = 0;
            int[] initBlockFast = config.getInitBlockFast();
            int[][] blockList16 = new int[LanRuoSiMgr.MAX_HEIGHT][LanRuoSiMgr.MAX_WIDTH];
            for (int y = 0; y < blockList16.length; y++) {
                for (int x = 0; x < blockList16[y].length; x++) {
                    blockList16[y][x] = initBlockFast[index++];
                }
            }
            tmpUserData.setBlockList(blockList16, 16);
        }

        tmpUserData.setInsertOption();
        userData = tmpUserData;
    }

    /**
     * 同步配置
     */
    public void syncConfig() {
        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        LanRuoSiProto.LanRuoSiSyncConfigRespMsg.Builder builder = LanRuoSiPb.parseSyncConfigRespMsg(config, player.getLanguage());
        player.sendPacket(Protocol.U_LANRUOSI_SYNC_CONFIG, builder);
    }

    /**
     * 同步玩家数据
     */
    public void syncUserData() {
        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        LanRuoSiUserData data = getUserData();
        if (data == null) {
            return;
        }

        LanRuoSiProto.LanRuoSiSyncUserDataRespMsg.Builder builder = LanRuoSiProto.LanRuoSiSyncUserDataRespMsg.newBuilder();
        builder.setEnergy(data.getEnergy());
        builder.setLastRecTime(data.getLastRecTime());
        player.sendPacket(Protocol.U_LANRUOSI_SYNC_USER_DATA, builder);
    }

    /**
     * 获取玩家数据
     */
    public LanRuoSiUserData getUserData() {

        // 检查体力恢复
        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        if (userData != null && config != null) {

            int logBeforeEnergy = userData.getEnergy();

            CalcPowerResult result = PowerHelper.calcPower(
                    userData.getLastRecTime() / 1000,
                    config.getEnergyRecTime() / 1000,
                    config.getEnergyRecCount(),
                    config.getMaxEnergy(),
                    userData.getEnergy());
            userData.setEnergy(result.getCurPower());
            userData.setLastRecTime(result.getLastRecoverTime() * 1000);

            // 日志
            if (userData.getEnergy() != logBeforeEnergy) {
                LogMgr.addLogLanRuoSiEnergy(new LogLanRuoSiEnergy(userData.getUserId(), userData.getActivityId(), 2, userData.getEnergy() - logBeforeEnergy, userData.getEnergy()));
            }
        }

        return userData;
    }

    /**
     * 使用体力药
     */
    public int useEnergyItem(int count) {

        if (count <= 0 || count > 99999) {
            return GameErrorCode.E_LANRUOSI_ACTIVITY_USE_COUNT_ERROR;
        }

        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        Property cost = new Property();
        cost.addProperty(config.getEnergyRecItemId(), BigInteger.valueOf(count));

        // 计算恢复数量
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(config.getEnergyRecItemId());
        BigInteger energyCount = goodsInfo.getParamList().get(0);
        int totalCount = energyCount.intValue() * count;

        // 扣道具
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.LanRuoSiActivity, eLogMoneyType.LanRuoSiUseEnergyItemCost)) {
            return GameErrorCode.E_LANRUOSI_ACTIVITY_ITEM_NO_ENOUGH;
        }

        // 加体力
        userData.setEnergy(userData.getEnergy() + totalCount);
        if (userData.getEnergy() > config.getMaxEnergy()) {
            userData.setLastRecTime(System.currentTimeMillis());
        }

        LanRuoSiProto.LanRuoSiUseEnergyItemRespMsg.Builder builder = LanRuoSiProto.LanRuoSiUseEnergyItemRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEnergy(userData.getEnergy());
        builder.setLastRecTime(userData.getLastRecTime());
        player.sendPacket(Protocol.U_LANRUOSI_USE_ENERGY_ITEM, builder);

        // 日志
        LogMgr.addLogLanRuoSiEnergy(new LogLanRuoSiEnergy(userData.getUserId(), userData.getActivityId(), 3, totalCount, userData.getEnergy()));

        return 0;
    }

    /**
     * 扣体力
     */
    public boolean reduceEnergy(int count) {
        if (userData.getEnergy() < count)
            return false;

        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        int maxEnergy = config.getMaxEnergy();
        boolean aboveMaxBefore = userData.getEnergy() >= maxEnergy;

        userData.setEnergy(userData.getEnergy() - count);
        if (aboveMaxBefore) {
            userData.setLastRecTime(System.currentTimeMillis());
        }
        // 日志
        LogMgr.addLogLanRuoSiEnergy(new LogLanRuoSiEnergy(userData.getUserId(), userData.getActivityId(), 1, count, userData.getEnergy()));

        return true;
    }

    /**
     * 消除
     */
    public int eliminateBlock(int fromX, int fromY, int toX, int toY, int multi) {

        LanRuoSiConfig config = LanRuoSiMgr.getConfig();
        List<Integer> costEnergyList = config.getCostEnergyList();
        int costEnergy = 1;
        if (multi == 1) costEnergy = costEnergyList.get(0);
        else if (multi == 8) costEnergy = costEnergyList.get(1);
        else if (multi == 16) costEnergy = costEnergyList.get(2);

        // 体力
        if (userData.getEnergy() < costEnergy) {
            return GameErrorCode.E_LANRUOSI_ACTIVITY_ENERGY_NO_ENOUGH;
        }

        // 消除
        EliminateResult result = EliminateLogic.eliminateBlock(config, userData, multi, fromX, fromY, toX, toY);
        if (result.getRet() != 0) {
            return result.getRet();
        }

        LanRuoSiProto.LanRuoSiEliminateRespMsg.Builder builder = LanRuoSiProto.LanRuoSiEliminateRespMsg.newBuilder();
        builder.setRet(result.getRet());

        // 处理结果

        // 消除的分数
        long baseScore = 0;
        // 所有消除的格子
        List<Block> allBlock = new ArrayList<>();
        long totalScore;

        //配置的基础值
        int perBaseDamage = config.getEliminateDamageList().get(multi == 16 ? 2 : multi == 8 ? 1 : 0);
        long perBaseScore = config.getAttackScoreList().get(multi == 16 ? 2 : multi == 8 ? 1 : 0);
        int size = result.getRoundResultList().size();
        for (int round = 0; round < size; round++) {
            EliminateRoundResult roundResult = result.getRoundResultList().get(round);
            //当前轮次每个格子的值（计额外加成）
            long perDamage = calBlockAttackHarm(round + 1, perBaseDamage, config);
            long perScore = calBlockAttackScore(round + 1, perBaseScore, config);
            for (EliminateStageResult stageResult : roundResult.getStageResultList()) {
                for (Block block : stageResult.getBlockList()) {
                    //赋值命中可得到的积分及产生的伤害
                    block.setAttackDamage(perDamage);
                    block.setAttackScore(perScore);
                    baseScore += block.getScore();
                    allBlock.add(block);
                }
            }
            TripleTownProto.TripleTownEliminateRoundMsg.Builder roundMsg = LanRuoSiPb.parseEliminateRoundMsg(roundResult);
            builder.addRoundMsgList(roundMsg);
        }

        int allBlockNum = allBlock.size();
        // 格子攻击妖怪
        List<Monster> monsters = userData.getMonsterList();
        AttackMonsterResult attackMonsterResult = attackMonster(monsters, result, config);
        totalScore = baseScore + attackMonsterResult.getScore();

        // 扣体力
        reduceEnergy(costEnergy);

        // 设置结果
        userData.setGuideIndex(result.getGuideIndex());
        userData.setBlockList(EliminateLogic.getCopyBlockList(result.getRoundResultList().get(result.getRoundResultList().size() - 1).getBlockList()), multi);
        userData.setScore(userData.getScore() + totalScore);

        String roundWave = userData.getRound() + "-" + userData.getWaveNum();
        // 妖怪刷新
        int dieSize = 0;
        for (Monster monster : monsters) {
            if(monster.getBlood() == 0){
                dieSize++;
            }
        }
        if(dieSize == monsters.size()){
            int waveNum = userData.getWaveNum();
            List<Monster> newList = new ArrayList<>();
            int newWaveNum = LanRuoSiMgr.getNextWaveMonsterList(waveNum, newList);
            if(waveNum != newWaveNum) {
                userData.setMonsterList(newList);
                userData.setWaveNum(newWaveNum);
                if(waveNum == config.getWaveMonsterMap().size()){
                    userData.setRound(1 + userData.getRound());
                }
            }
        }

        // 组装积分奖励
        int scoreItemId = LanRuoSiMgr.getConfig().getScoreItemId();
        Property property = new Property();
        property.addProperty(scoreItemId, BigInteger.valueOf(baseScore));

        // 加奖励(消除积分 与 攻击积分 分开)
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.LanRuoSiActivity, eLogMoneyType.LanRuoSiEliminateGet);
        if(attackMonsterResult.getScore() > 0) {
            property = new Property();
            property.addProperty(scoreItemId, BigInteger.valueOf(attackMonsterResult.getScore()));
            player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.LanRuoSiActivity, eLogMoneyType.LanRuoSiAttackGet);
        }

        // 榜单
        player.notifyListener(eGamePlayerEventType.LanRuoSiActivityScoreRank.getValue(), userData.getScore());
        player.notifyListener(eGamePlayerEventType.LanRuoSiActivityCrossScoreRank.getValue(), userData.getScore());

        //成就
        //击败
        for (Monster monster : attackMonsterResult.getDieList()) {
            player.notifyListener(eGamePlayerEventType.LanRuoSiAttackMonsterNumByType.getValue(), new ConditionTypeValueArgs(monster.getId(), 1));
        }
        //累计击败
        if(attackMonsterResult.getDieList().size() > 0){
            int num = attackMonsterResult.getDieList().size();
            player.notifyListener(eGamePlayerEventType.LanRuoSiAttackMonsterTotalNum.getValue(), Long.valueOf(num));
        }
        //累计伤害
        player.notifyListener(eGamePlayerEventType.LanRuoSiAttackMonsterTotalDamage.getValue(), attackMonsterResult.getDamage());
        //单次消除
        player.notifyListener(eGamePlayerEventType.LanRuoSiAttackMonsterOnceMaxBlock.getValue(), Long.valueOf(allBlockNum));

        // 返回
        builder.setGameData(LanRuoSiPb.parseGameDataMsg(userData, multi));
        player.sendPacket(Protocol.U_LANRUOSI_ELIMINATE_BLOCK, builder);

        // 消除日志1
        EliminateRoundResult logRoundResult1 = result.getRoundResultList().get(0);
        Property logBombProp = new Property();
        long logScore = 0;
        int logCount = 0;
        for (EliminateStageResult stageResult : logRoundResult1.getStageResultList()) {
            for (Block block : stageResult.getBlockList()) {
                logScore += block.getScore();
                //加命中积分
                if(block.isAttack()){
                    logScore += block.getAttackScore();
                }
                logCount++;
                if (EliminateLogic.isBomb(block.getC())) {
                    logBombProp.addProperty(block.getC(), BigInteger.ONE);
                }
            }
        }
        List<Integer> monsterIdList = new ArrayList<>();
        for (Monster monster : attackMonsterResult.getMonsterList()) {
            monsterIdList.add(monster.getId());
        }
        String hitMonster = StringUtils.listToString(monsterIdList, "|");
        String hitHarm = StringUtils.listToString(logRoundResult1.getHarmList(), "|");
        String blood = StringUtils.listToString(logRoundResult1.getBloodList(), "|");
        LogMgr.addLogLanRuoSiEliminate1(new LogLanRuoSiEliminate1(
                userData.getUserId(), userData.getActivityId(), multi == 16 ? 2 : multi == 8 ? 1 : 0, PropertyHelper.parsePropertyToString(logBombProp), logCount, logScore,
                hitMonster, hitHarm, blood, roundWave
        ));

        // 消除日志2
        List<EliminateRoundResult> logRoundResultList = result.getRoundResultList();
        if (logRoundResultList.size() > 1) {
            logScore = 0;
            logCount = 0;
            int logMaxCon = 1;
            //汇总伤害
            List<Integer> harmList = new ArrayList<>();
            for (Monster monster : attackMonsterResult.getMonsterList()) {
                harmList.add(0);
            }
            for (int i = 1; i < logRoundResultList.size(); i++) {
                EliminateRoundResult logRoundResult2 = logRoundResultList.get(i);
                if (logRoundResult2.getType() != 1) {
                    continue;
                }
                logMaxCon++;
                for (EliminateStageResult stageResult : logRoundResult2.getStageResultList()) {
                    for (Block block : stageResult.getBlockList()) {
                        logScore += block.getScore();
                        //加命中积分
                        if(block.isAttack()){
                            logScore += block.getAttackScore();
                        }
                        logCount++;

                    }
                }
                for (int k = 0; k < logRoundResult2.getHarmList().size(); k++) {
                    harmList.set(k, harmList.get(k) + logRoundResult2.getHarmList().get(k));
                }
            }
            String hitHarm2 = StringUtils.listToString(harmList, "|");
            List<Integer> bloodList = new ArrayList<>();
            for (Monster monster : attackMonsterResult.getMonsterList()) {
                bloodList.add(monster.getBlood());
            }
            String blood2 = StringUtils.listToString(bloodList, "|");
            LogMgr.addLogLanRuoSiEliminate2(new LogLanRuoSiEliminate2(
                    userData.getUserId(), userData.getActivityId(), multi == 16 ? 2 : multi == 8 ? 1 : 0, logMaxCon, logCount, logScore,
                    hitMonster, hitHarm2, blood2, roundWave
            ));
        }
        return 0;
    }

    /**
     * 攻击妖怪
     */
    private AttackMonsterResult attackMonster(List<Monster> monsters, EliminateResult eliminateResult, LanRuoSiConfig config) {
        AttackMonsterResult attackResult = new AttackMonsterResult();
        int size = eliminateResult.getRoundResultList().size();

        attackResult.setMonsterList(monsters);
        //总值
        long allScore = 0l;
        long allDamage = 0l;

        for (int round = 0; round < size; round++) {
            EliminateRoundResult roundResult = eliminateResult.getRoundResultList().get(round);
            for(int i = 0; i < monsters.size(); i++){
                roundResult.getHarmList().add(0);
            }
            for (EliminateStageResult stageResult : roundResult.getStageResultList()) {
                for (Block block : stageResult.getBlockList()) {
                    //已命中过
                    if (block.isAttack()) {
                        continue;
                    }
                    for (int i = 0; i < monsters.size(); i++) {
                        Monster monster = monsters.get(i);
                        if (monster.getBlood() <= 0) {
                            continue;
                        }
                        //未命中
                        if (!monster.getCols().contains(block.getX())) {
                            continue;
                        }
                        block.setAttack(true);
                        block.setMonsterId(monster.getId());
                        //是否打死
                        if (block.getAttackDamage() >= monster.getBlood()) {
                            monster.setBlood(0);
                            attackResult.getDieList().add(monster);
                        } else {
                            monster.setBlood(monster.getBlood() - (int) block.getAttackDamage());
                        }
                        //记录对每只怪的伤害
                        roundResult.getHarmList().set(i, roundResult.getHarmList().get(i) + (int)block.getAttackDamage());
                        allDamage += block.getAttackDamage();
                        allScore += block.getAttackScore();
                    }
                }
            }
            //记录本轮后血量情况
            for (Monster monster : monsters) {
                roundResult.getBloodList().add(monster.getBlood());
            }
        }
        attackResult.setDamage(allDamage);
        attackResult.setScore(allScore);
        return attackResult;
    }

    /**
     * 计算第x轮的格子伤害（x从1开始）
     */
    public long calBlockAttackHarm(int round, long value, LanRuoSiConfig config) {
        // 基础伤害
        BigDecimal baseHarm = BigDecimal.valueOf(value);
        // 放大倍数
        int addition;
        Map<Integer, LanRuoSiScoreConfigInfo> scoreConfigMap = config.getScoreConfigMap();
        if (scoreConfigMap.containsKey(round)) {
            addition = scoreConfigMap.get(round).getHarmAdd();
        } else {
            // 没有配置的话，就取最大值
            int maxRound = -1;
            for (LanRuoSiScoreConfigInfo scoreConfig : scoreConfigMap.values()) {
                if (scoreConfig.getContinuousNum() > maxRound) maxRound = scoreConfig.getContinuousNum();
            }
            addition = scoreConfigMap.get(maxRound).getHarmAdd();
        }
        // 结果
        return baseHarm.multiply(BigDecimal.valueOf(1000 + addition)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
    }

    /**
     * 计算第x轮的格子积分（x从1开始）
     */
    public long calBlockAttackScore(int round, long value, LanRuoSiConfig config) {
        // 基础伤害
        BigDecimal baseScore = BigDecimal.valueOf(value);
        // 放大倍数
        int addition;
        Map<Integer, LanRuoSiScoreConfigInfo> scoreConfigMap = config.getScoreConfigMap();
        if (scoreConfigMap.containsKey(round)) {
            addition = scoreConfigMap.get(round).getNpcScoreAdd();
        } else {
            // 没有配置的话，就取最大值
            int maxRound = -1;
            for (LanRuoSiScoreConfigInfo scoreConfig : scoreConfigMap.values()) {
                if (scoreConfig.getContinuousNum() > maxRound) maxRound = scoreConfig.getContinuousNum();
            }
            addition = scoreConfigMap.get(maxRound).getNpcScoreAdd();
        }
        // 结果
        return baseScore.multiply(BigDecimal.valueOf(1000 + addition)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
    }
}
